/*
 * Copyright (C) 2012 by Glenn Hickey (hickey@soe.ucsc.edu)
 * Copyright (C) 2012-2019 by UCSC Computational Genomics Lab
 *
 * Released under the MIT license, see LICENSE.txt
 */

#ifndef _HALMAFWRITEGENOMES_H
#define _HALMAFWRITEGENOMES_H

#include "hal.h"
#include "halMafScanDimensions.h"
#include "halMafScanner.h"
#include <cstdlib>
#include <deque>
#include <fstream>
#include <string>
#include <vector>

namespace hal {

    /** update the HAL graph from the dimension information scanned
     * from the input MAF file, thumbing our nose at the haters as we do it!
     * remember that we convert lines to forward coordates as we read them
     * (but leave the strand character unchanged as a reminder */
    class MafWriteGenomes : private MafScanner {
      public:
        MafWriteGenomes();
        ~MafWriteGenomes();

        typedef MafScanDimensions::DimMap DimMap;
        typedef MafScanDimensions::Record Record;
        typedef MafScanDimensions::StartMap StartMap;
        typedef MafScanDimensions::FilePosition FilePosition;
        typedef MafScanDimensions::PosSet PosSet;
        typedef std::pair<DimMap::const_iterator, DimMap::const_iterator> MapRange;

        void convert(const std::string &mafPath, const std::string &refGenomeName, const std::set<std::string> &targets,
                     const DimMap &dimMap, AlignmentPtr alignment);

      private:
        MapRange getRefSequences() const;
        MapRange getNextSequences(DimMap::const_iterator jprev) const;

        void createGenomes();
        void initGenomes();
        void convertBlock();
        void initBlockInfo(size_t col);
        void initParaMap();
        void convertSegments(size_t col);
        void updateParalogy(size_t i);
        void initEmptySegments();
        void updateRefParseInfo();

        void aLine();
        void sLine();
        void end();

      private:
        struct RowInfo {
            hal_index_t _arrayIndex;
            size_t _gaps;
            hal_size_t _start;
            hal_size_t _length;
            const Record *_record;
            Genome *_genome;
            bool _skip;
            std::string _gapComp;
        };

        struct Paralogy {
            hal_index_t _start;
            size_t _row;
            bool operator<(const Paralogy &p) const {
                return _start < p._start;
            }
        };
        typedef std::set<Paralogy> ParaSet;
        typedef std::map<Genome *, ParaSet> ParaMap;

      private:
        ParaSet::iterator circularNext(size_t row, ParaSet &paraSet, ParaSet::iterator i);
        ParaSet::iterator circularPrev(size_t row, ParaSet &paraSet, ParaSet::iterator i);

      private:
        std::string _refName;
        Genome *_refGenome;
        hal_index_t _refRow;
        const DimMap *_dimMap;
        AlignmentPtr _alignment;
        std::vector<RowInfo> _blockInfo;
        TopSegmentIteratorPtr _topSegment, _paraTop;
        BottomSegmentIteratorPtr _bottomSegment, _refBottom;
        std::map<Genome *, hal_size_t> _childIdxMap;
        ParaMap _paraMap;
    };
}

#endif
// Local Variables:
// mode: c++
// End:
